import type { ProcessorWorkerReplyWorkerMessage, ProcessorWorkerSendWorkerData, ProcessorWorkerSendWorkerMessage } from './types'

function to16kHz(audioData: Float32Array): Float32Array {
  const data = new Float32Array(audioData)
  const fitCount = Math.round(data.length * (16000 / 44100))
  const newData = new Float32Array(fitCount)
  const springFactor = (data.length - 1) / (fitCount - 1)
  ;[newData[0]] = data
  for (let i = 1; i < fitCount - 1; i += 1) {
    const tmp = i * springFactor
    const before = Math.floor(tmp).toFixed() as unknown as number
    const after = Math.ceil(tmp).toFixed() as unknown as number
    const atPoint = tmp - before
    newData[i] = data[before] + (data[after] - data[before]) * atPoint
  }
  newData[fitCount - 1] = data[data.length - 1]
  return newData
}

function to16BitPCM(input: Float32Array): DataView {
  const dataLength = input.length * (16 / 8)
  const dataBuffer = new ArrayBuffer(dataLength)
  const dataView = new DataView(dataBuffer)
  let offset = 0
  for (let i = 0; i < input.length; i += 1, offset += 2) {
    const s = Math.max(-1, Math.min(1, input[i]))
    dataView.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true)
  }
  return dataView
}

function transcode(data: ProcessorWorkerSendWorkerData): void {
  const audioData = data.original
  const output: Array<number> = Array.from(new Uint8Array(to16BitPCM(to16kHz(audioData)).buffer))

  globalThis.postMessage({
    type: 'success',
    data: {
      audioData: output,
      uuid: data.uuid,
    },
  } as ProcessorWorkerReplyWorkerMessage)
}

function handleRun(data: ProcessorWorkerSendWorkerData): void {
  transcode(data)
}

globalThis.addEventListener('message', (event: MessageEvent<ProcessorWorkerSendWorkerMessage>) => {
  const { type, data } = event.data
  if (type === 'send') {
    handleRun(data!)
  }
})
